package pl.edu.agh.anomalyids.lerad.listener;

import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import pl.edu.agh.anomalyids.lerad.aspect.enums.Match;
import pl.edu.agh.anomalyids.lerad.rule.RulesHolder;
import pl.edu.agh.anomalyids.network.Packet;
import pl.edu.agh.anomalyids.network.listener.PacketListener;

public class PacketVerifier implements PacketListener {

	public final static int MAXTHREADSCOUNT = 500;

	private int threadsCount = 0;
	private Logger logger = LoggerFactory.getLogger(PacketVerifier.class);

	public RulesHolder rulesHolder;

	public PacketVerifier(RulesHolder rulesHolder) {
		this.rulesHolder = rulesHolder;
	}

	@Override
	public void onPacketArrived(Packet packet) {
		checkPacket(packet);
	}

	public void checkPacket(Packet packet) {
		if (threadsCount >= MAXTHREADSCOUNT) {
			logger.warn("Not enough threads in pool to validate packet. Packet omitted.");
			return;
		}
		new CheckingThread(packet).start();
	}

	public class CheckingThread extends Thread {

		private Packet packet;

		public CheckingThread(Packet packet) {
			this.packet = packet;
		}

		public void run() {			
			incrementThreadsCount();
			Pair<Match, Double> match = rulesHolder.passesRule(packet);
			if (match.getLeft() == Match.DIFFER) {
				 logValidationFail(String.format("ALERT: Packet is a potential threat (Score %s)\n%s",match.getRight(),
				 packet.toString()), true);
			} else if (match.getLeft() == Match.UNKNOWN) {
				logValidationFail(String.format(
						"WARNING: Packet was not recognized by any rule\n%s",
						packet.toString()), false);
			}
			decrementThreadsCount();
		}
	}

	private synchronized void incrementThreadsCount() {
		threadsCount++;
	}

	private synchronized void decrementThreadsCount() {
		threadsCount--;
	}

	private synchronized void logValidationFail(String message,
			boolean isCritical) {
		if (isCritical) {
			logger.error(message);
		} else {
			logger.warn(message);
		}
	}
}
